package gatperdut.chato.core.interpreter.actions;

import gatperdut.chato.constants.CSConstantsCommandResult.CommandExecutionResult;
import gatperdut.chato.constants.CSConstantsFood;
import gatperdut.chato.core.characters.BaseController;
import gatperdut.chato.core.interpreter.actions.generic.Action;
import gatperdut.chato.core.interpreter.grammar.comminfo.SpillInfo;
import gatperdut.chato.core.item.DrinkController;
import gatperdut.chato.core.item.ItemController;

public class SpillAction extends Action {

    public SpillAction( SpillInfo info, BaseController entityController ) {
        super( info, entityController );
    }

    @Override
    public CommandExecutionResult perform() {
        checkForRunningCraft();

        DrinkController fromDC = null;
        DrinkController intoDC = null;

        if ( emptyEmote() ) {
            getEntityController().tx( "Empty emotes are not allowed." );
            return CommandExecutionResult.OK;
        }

        String emote = getLastPartEmote();
        if ( emote == null ) {
            getEntityController().tx( "Check your emote." );
            return CommandExecutionResult.OK;
        }

        if ( !checkUnindexedWord( getInfo().getToBeSpilled() ) ) {
            return CommandExecutionResult.OK;
        }
        ItemController from = getEntityController().getInventoryController().getHeldItemController( getInfo().getToBeSpilled() );
        if ( from == null ) {
            getEntityController().tx( "You don't seem to be holding that." );
            return CommandExecutionResult.OK;
        }
        if ( !from.isDrinkable() ) {
            getEntityController().tx( from.getShortDesc() + " cannot hold any liquid to be spilled." );
            return CommandExecutionResult.OK;
        }

        fromDC = (DrinkController) from.getAmountController();

        if ( fromDC.hasNoPortionLeft() ) {
            getEntityController().tx( from.getShortDesc() + " is empty." );
            return CommandExecutionResult.OK;
        }

        if ( getInfo().getAmount() != null && getInfo().getAmount() <= 0 ) {
            getEntityController().tx( "That amount to spill does not make sense, does it?" );
            return CommandExecutionResult.OK;
        }

        ItemController into = null;
        if ( getInfo().getSpillInto() != null ) {
            into = findInRoomOrInventory( getInfo().getSpillInto(), getInfo().isGround() );
            if ( into == null ) {
                getEntityController().tx( "Where do you want to spill " + from.getShortDesc() + "?" );
                return CommandExecutionResult.OK;
            }
            if ( from == into ) {
                getEntityController().tx( "You cannot spill the contents of " + from.getShortDesc() + " into itself!" );
                return CommandExecutionResult.OK;
            }
            if ( !into.isDrinkable() ) {
                getEntityController().tx( into.getShortDesc() + " cannot hold liquids." );
                return CommandExecutionResult.OK;
            }

            intoDC = (DrinkController) into.getAmountController();

            if ( !intoDC.hasNoPortionLeft() && !fromDC.containsThisFluid( intoDC.getFluidContent() ) ) {
                getEntityController().tx( "You cannot mix different liquids." );
                return CommandExecutionResult.OK;
            }
            if ( intoDC.hasWholePortion() ) {
                String fluidName = CSConstantsFood.getFluidName( intoDC.getFluidContent() );
                getEntityController().tx( into.getShortDesc() + " cannot hold any more " + fluidName + "." );
                return CommandExecutionResult.OK;
            }
        }

        int amountToSpill;
        if ( getInfo().getAmount() == null ) {
            amountToSpill = fromDC.getPortion();
        }
        else {
            amountToSpill = Math.min( fromDC.getPortion(), getInfo().getAmount() );
        }

        if ( into == null ) {
            fromDC.consumePortion( amountToSpill );
            getEntityController().getEchoes().txSpillOnGround( from, fromDC.hasNoPortionLeft(), emote );
        }
        else {
            amountToSpill = Math.min( amountToSpill, intoDC.getPortionLeftToMax() );

            fromDC.consumePortion( amountToSpill );
            if ( intoDC.isSetWithEmptyContainerOnTop() ) {
                ItemController newContainer = into.spawnFromSetOfEmptyContainers( fromDC.getFluidContent(), amountToSpill );
                getEntityController().handleSpawnedItem( into.getContainerController(), newContainer );
            }
            else {
                intoDC.addPortion( amountToSpill );
            }
            getEntityController().getEchoes().txSpillInContainer( from, into, fromDC.hasNoPortionLeft(), emote );

        }

        if ( fromDC.isSetWithEmptyContainerOnTop() ) {
            ItemController newContainer = from.spawnFromSetOfNonEmptyContainers();
            getEntityController().handleSpawnedItem( from.getContainerController(), newContainer );
        }

        return CommandExecutionResult.OK;
    }

    @Override
    public SpillInfo getInfo() {
        return (SpillInfo) super.getInfo();
    }

    @Override
    public boolean interruptsCrafting() {
        return false;
    }

}
